import { createSelector, createSlice } from '@reduxjs/toolkit';

import {
	initThemeSettings,
	toggleAuxiliaryColorModes,
	toggleGrayscaleMode
} from '@/common/theme/shared';
import { getPaletteColorByNumber } from '@/layout/modules/color';
import type { AppThunk } from '@/store';
import { localStg } from '@/utils/storage';

import type { PayloadAction } from '@reduxjs/toolkit';

interface InitialStateType {
	settings: App.Theme.ThemeSetting;
}

export type DeepPartial<T> = {
	[P in keyof T]?: T[P] extends (infer U)[]
		? DeepPartial<U>[]
		: T[P] extends ReadonlyArray<infer U>
			? ReadonlyArray<DeepPartial<U>>
			: DeepPartial<T[P]>;
};

const initialState: InitialStateType = {
	settings: initThemeSettings()
};

/**
 * 主题设置切片
 *
 * @param state 当前状态
 * @param action 动作对象
 * @returns 新状态
 */
export const themeSlice = createSlice({
	initialState,
	name: 'theme',
	reducers: {
		/**
		 * 反转横向混合模式
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		changeReverseHorizontalMix(state, { payload }: PayloadAction<boolean>) {
			state.settings.layout.reverseHorizontalMix = payload;
		},

		/**
		 * 重置主题设置
		 *
		 * @returns 初始状态
		 */
		resetTheme() {
			return initialState;
		},

		/**
		 * 设置色彩弱化
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setColourWeakness(state, { payload }: PayloadAction<boolean>) {
			toggleAuxiliaryColorModes(payload);
			state.settings.colourWeakness = payload;
		},

		/**
		 * 设置固定头部和标签
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setFixedHeaderAndTab(state, { payload }: PayloadAction<boolean>) {
			state.settings.fixedHeaderAndTab = payload;
		},

		/**
		 * 设置页脚
		 *
		 * @param state 当前状态
		 * @param payload 页脚配置
		 */
		setFooter(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['footer']>>) {
			Object.assign(state.settings.footer, payload);
		},

		/**
		 * 设置灰度模式
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setGrayscale(state, { payload }: PayloadAction<boolean>) {
			toggleGrayscaleMode(payload);
			state.settings.grayscale = payload;
		},

		/**
		 * 设置头部
		 *
		 * @param state 当前状态
		 * @param payload 头部配置
		 */
		setHeader(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['header']>>) {
			Object.assign(state.settings.header, payload);
		},

		/**
		 * 设置信息跟随主色
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setIsInfoFollowPrimary(state, { payload }: PayloadAction<boolean>) {
			state.settings.isInfoFollowPrimary = payload;
		},

		/**
		 * 设置仅展开当前父级菜单
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setIsOnlyExpandCurrentParentMenu(state, { payload }: PayloadAction<boolean>) {
			state.settings.isOnlyExpandCurrentParentMenu = payload;
		},

		/**
		 * 设置布局模式
		 *
		 * @param state 当前状态
		 * @param payload 布局模式
		 */
		setLayoutMode(state, { payload }: PayloadAction<UnionKey.ThemeLayoutMode>) {
			state.settings.layout.mode = payload;
		},

		/**
		 * 设置布局滚动模式
		 *
		 * @param state 当前状态
		 * @param payload 滚动模式
		 */
		setLayoutScrollMode(state, { payload }: PayloadAction<UnionKey.ThemeScrollMode>) {
			state.settings.layout.scrollMode = payload;
		},

		/**
		 * 设置页面
		 *
		 * @param state 当前状态
		 * @param payload 页面配置
		 */
		setPage(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['page']>>) {
			Object.assign(state.settings.page, payload);
		},

		/**
		 * 设置推荐色彩
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setRecommendColor(state, { payload }: PayloadAction<boolean>) {
			state.settings.recommendColor = payload;
		},

		/**
		 * 设置侧边栏
		 *
		 * @param state 当前状态
		 * @param payload 侧边栏配置
		 */
		setSider(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['sider']>>) {
			Object.assign(state.settings.sider, payload);
		},

		/**
		 * 设置侧边栏反色
		 *
		 * @param state 当前状态
		 * @param payload 布尔值
		 */
		setSiderInverted(state, { payload }: PayloadAction<boolean>) {
			state.settings.sider.inverted = payload;
		},

		/**
		 * 设置标签
		 *
		 * @param state 当前状态
		 * @param payload 标签配置
		 */
		setTab(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['tab']>>) {
			Object.assign(state.settings.tab, payload);
		},

		/**
		 * 设置水印
		 *
		 * @param state 当前状态
		 * @param payload 水印配置
		 */
		setWatermark(state, { payload }: PayloadAction<Partial<App.Theme.ThemeSetting['watermark']>>) {
			Object.assign(state.settings.watermark, payload);
		},

		/**
		 * 更新主题颜色
		 *
		 * @param state 当前状态
		 * @param payload 颜色值和键
		 */
		updateThemeColors(
			state,
			{ payload: { color, key } }: PayloadAction<{ color: string; key: App.Theme.ThemeColorKey }>
		) {
			let colorValue = color;

			if (state.settings.recommendColor) {
				// 获取由提供的颜色和颜色名称生成的颜色调色板，并使用合适的颜色

				colorValue = getPaletteColorByNumber(color, 500, true);
			}

			if (key === 'primary') {
				state.settings.themeColor = colorValue;
			} else {
				state.settings.otherColor[key] = colorValue;
			}
		}
	},
	selectors: {
		getThemeSettings: theme => theme.settings
	}
});

export const { getThemeSettings } = themeSlice.selectors;

export const {
	changeReverseHorizontalMix,
	resetTheme,
	setColourWeakness,
	setFixedHeaderAndTab,
	setFooter,
	setGrayscale,
	setHeader,
	setIsInfoFollowPrimary,
	setIsOnlyExpandCurrentParentMenu,
	setLayoutMode,
	setLayoutScrollMode,
	setPage,
	setRecommendColor,
	setSider,
	setSiderInverted,
	setTab,
	setWatermark,
	updateThemeColors
} = themeSlice.actions;

// 计算属性选择器
export const themeColors = createSelector(
	[getThemeSettings],
	({ isInfoFollowPrimary, otherColor, themeColor }) => {
		const colors: App.Theme.ThemeColor = {
			primary: themeColor,
			...otherColor,
			info: isInfoFollowPrimary ? themeColor : otherColor.info
		};
		return colors;
	}
);

export const settingsJson = createSelector([getThemeSettings], settings => {
	return JSON.stringify(settings);
});

/** Cache theme settings */
export const cacheThemeSettings = (): AppThunk => (_, getState) => {
	const isProd = import.meta.env.PROD;

	if (!isProd) return;

	localStg.set('themeSettings', getThemeSettings(getState()));
};
